package sjc;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.io.IOException;

/**
 * Curator的第一种Leader选举机制的代码实验-Leader Latch
 * leader latch核心思想: 初始化多个LeaderLatch，等待几秒钟后，Curator会自动从中选举出Leader。
 *
 * Leader Latch选举的本质是连接ZooKeeper，然后在“/leader”路径为每个LeaderLatch创建临时有序节点：
 * 在创建临时节点时，org.apache.curator.framework.recipes.leader.LeaderLatch 的 checkLeadership(List<String> children) 方法会将选举路径（/leader）下面的所有节点按照序列号排序，
 * 1. 如果当前节点的序列号最小，则将该节点设置为leader。
 * 2. 反之则监听比当前节点序列号小一位的节点的状态
 *    - 因为每次都会选择序列号最小的节点为leader，所以在比当前节点序列号小一位的节点未被删除前，当前节点是不可能变成leader的。
 * 3. 如果监听的节点被删除，则会触发重新选举方法: reset()
 *
 * Leader Latch选举策略在选举出leader后，该LeaderLatch实例会一直占有领导权，直到调用 close() 方法关闭当前主节点，然后其他LeaderLatch实例才会再次选举leader。
 *
 * 这种策略适合主备应用，当主节点意外宕机之后，多个从节点会自动选举其中一个为新的主节点（Master节点）。
 *
 * 在idea中更改APP_ID，开启多个main并行执行，即可模拟集群选举效果。
 */
public class LeaderLatchTest {
    private static final String PATH = "/leader";
    private static final String APP_ID = "005";

    public static void main(String[] args) throws IOException {
        CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.72.133:2181", new ExponentialBackoffRetry(1000, 3));
        client.start();

        LeaderLatch leaderLatch = new LeaderLatch(client, PATH, APP_ID);
        leaderLatch.addListener(new LeaderLatchListener() {
            /**
             * isLeader 中的方法会在实例被选为主节点后被执行, 而notLeader中的不会被执行,
             * 如果主节点被失效, 会进行重新选主
             */
            @Override
            public void isLeader() {
                System.out.println("======= [LeaderLatch]我是主节点, app_id={" + leaderLatch.getId() + "} =========");
            }

            // 当丢失leader的时候被执行
            @Override
            public void notLeader() {
                System.out.println("======= [LeaderLatch]我不是主节点, app_id={" + leaderLatch.getId() + "} =========");
            }
        });

        try {
            leaderLatch.start();
            while (true) {
                Thread.sleep(10000);
                System.out.println("======= " + leaderLatch.getLeader() + " ==========");
            }
        } catch (Exception e) {
            e.printStackTrace();
            leaderLatch.close();
            client.close();
        }
    }
}
